package com.snap.vseries.update;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.TextView;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.orhanobut.logger.Logger;
import com.snap.vseries.R;
import com.snap.vseries.bean.SerialPortDevice;
import com.snap.vseries.framework.MoleExecutor;
import com.snap.vseries.utils.FileUtils;
import com.snap.vseries.utils.StringUtils;
import com.snap.vseries.utils.ToastUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.DecimalFormat;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import static com.snap.vseries.AppConfig.SERIAL_BAUD_RATE;
import static com.snap.vseries.AppConfig.SERIAL_PORT;


public class UpdateManager {
    private static UpdateManager sInstance = new UpdateManager();
    private UpdateSerialPortHelper serialPortHelper = new UpdateSerialPortHelper(new SerialPortDevice(SERIAL_PORT, SERIAL_BAUD_RATE));
    private ExecutorService singlePool = Executors.newSingleThreadExecutor();
    private List<UpdateConfigBean> configs;
    private boolean logEnable = true;

    private UpdateManager() {
    }

    public static UpdateManager getInstance() {
        return sInstance;
    }

    public void doUpdate(Context context, boolean force) {
        Dialog dialog = new Dialog(context, R.style.DimDialogStyle);
        dialog.setContentView(R.layout.dialog_loading);
        TextView contentTv = dialog.findViewById(R.id.content_tv);
        contentTv.setText("更新检测中");
        dialog.setCanceledOnTouchOutside(false);
        dialog.setCancelable(false);
        dialog.show();

        MoleExecutor.getInstance().execute(() -> {
            File configFile = new File("/sdcard/update.json");
            if (!configFile.exists()) {
                ToastUtils.get().showText("未找到升级配置文件");
                dialog.dismiss();
                return;
            }
            String configStr = FileUtils.readJsonFile(configFile);
            Gson gson = new Gson();
            Type type = new TypeToken<List<UpdateConfigBean>>() {
            }.getType();
            configs = gson.fromJson(configStr, type);
            if (configs == null) {
                ToastUtils.get().showText("升级配置文件解析失败");
                dialog.dismiss();
                return;
            } else if (configs.size() == 0) {
                ToastUtils.get().showText("升级配置文件空，无需更新");
                dialog.dismiss();
                return;
            }
            try {
                //不同于320，v1带屏版本，采光和温度是同一固件，只用更新一个固件就可以了
                int configIndex = 0;
                serialPortHelper.open();
                int index = configs.get(configIndex).getIndex();

                String v = getVersion(index);
                if (v == null) v = getVersion(index);
                if (TextUtils.isEmpty(v)) {
                    if (logEnable) Logger.e("第%d模块未能获取下位机版本号", v);
                }

                //版本比较
                UpdateConfigBean need = null;
                byte[] fileDate = null;
                if (TextUtils.isEmpty(v)) {
                    //如果读不到下位机版本号，但是勾选了强制更新的话，进行固件更新
                    if (force) {
                        if (logEnable) Logger.e("模块强制进行更新");
                        String name = configs.get(configIndex).getName();
                        fileDate = FileUtils.readNormalFile(new File("/sdcard/" + name));
                        if (fileDate == null) {
                            if (logEnable) Logger.e("未能读取文件" + name);
                        } else {
                            need = configs.get(configIndex);
                        }
                    }
                } else if (StringUtils.compareVersion(configs.get(configIndex).getVersion(), v) > 0) {
                    if (logEnable) Logger.e("模块需要更新");
                    String name = configs.get(configIndex).getName();
                    fileDate = FileUtils.readNormalFile(new File("/sdcard/" + name));
                    if (fileDate == null) {
                        if (logEnable) Logger.e("未能读取文件" + name);
                    } else {
                        need = configs.get(configIndex);
                    }
                }

                if (need == null) {
                    ToastUtils.get().showText("无可更新模块！");
                    return;
                }
                contentTv.post(() -> contentTv.setText("更新中..."));

                OnUpdateListener listener = percent -> contentTv.post(() -> {
                    String p = new DecimalFormat("#.#").format(percent * 100) + "%";
                    contentTv.setText(String.format("更新中(%s)\n,共1个", p));
                });

                UpdateTask2 task = new UpdateTask2(serialPortHelper, need.getIndex(),
                        fileDate, need.getVersion());
                task.setListener(listener);
                FutureTask<UpdateRes> futureTask = new FutureTask<>(task);
                singlePool.submit(futureTask);
                try {
                    UpdateRes res = futureTask.get();
                    if (res.isSuc()) {
                        ToastUtils.get().showText("模块更新成功");
                        Logger.e("模块更新成功");
                    } else {
                        ToastUtils.get().showText("模块写入固件失败，原因：" + res.getMsg());
                        Logger.e("模块写入固件失败，原因：%s", res.getMsg());
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                serialPortHelper.close();
                dialog.dismiss();
            }
        });
    }

    /**
     * 读取设备当前固件版本号
     *
     * @param index
     * @return
     */
    private String getVersion(int index) {
        Bundle bundle = null;
        try {
            bundle = serialPortHelper.execute(UpdateCmd.getHardInfo(index));
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        }
        if (!bundle.getBoolean("suc")) {
            return null;
        }
        byte[] res = bundle.getByteArray("data");
        int v1 = res[11];
        int v2 = res[12];
        int v3 = res[13];
        String currentVersion = v1 + "." + v2 + "." + v3;
        return currentVersion;
    }
}
